import sys
import time

import ntplib
import uvicorn
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

sys.path.append("../")
sys.path.append("../../")

from src.application import pages, private
from src.application.vo import *
from src.database import DataSet, DataDict, UserDict
from src.utils import sha256hex

data_path = "../../data/"

app = FastAPI()
app.include_router(pages.router)
app.include_router(private.router)

# CORS
origins = [
    "http://localhost",
    "http://localhost:8888",
    "http://localhost:8080",
    "http://101.42.119.24",
]
app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)


# controllers
@app.get("/")
async def echo():
    # 这个函数可以用来粗略估计网络延迟
    pass


@app.get("/time")
async def get_time():
    # 获取主机当前时间
    # 这个函数可以用来粗略对齐时间
    return time.time()


@app.get("/time/offset")
async def get_time_offset():
    # 获取主机相对于第三方的时间偏移
    # 单位是 ms
    c = ntplib.NTPClient()
    res = c.request("time.windows.com")
    return res.offset * 1000


@app.post("/sessions")
async def login(user: UserVO) -> ResponseVO:
    username = user.username
    password = user.password
    # 登录
    u = UserDict()
    u = u.load_from_config()
    password = sha256hex(password)
    if username in u.data:
        if u.data[username] == password:
            # 登录成功，返回成功
            return ResponseVO(200, "Successfully login.")
        else:
            # 密码错误，返回错误码
            return ResponseVO(700, "Username does not exist or Password is wrong.")
    else:
        # 用户不存在，返回错误码
        return ResponseVO(700, "Username does not exist or Password is wrong.")


@app.post("/users")
async def register(user: UserVO) -> ResponseVO:
    username = user.username
    password = user.password
    # 注册，将用户信息暂时保存到 data/users.data
    u = UserDict()
    u = u.load_from_config()
    password = sha256hex(password)
    if username in u.data:
        # 用户已经存在，返回错误码
        return ResponseVO(701, "Username exists.")
    else:
        u.add_user(username, password)
        u.save_to_config()
        # 返回成功状态码
        return ResponseVO(200, "Successfully register.")


# 数据集
@app.get("/datasets")
async def get_datasets():
    d = DataDict()
    d = d.load_from_config()
    previous = d.data
    current = dict()
    for k, v in previous.items():
        # 为了兼容，若没有is_public字段，视为共有数据集
        if 'is_public' not in v or v['is_public']:
            current[k] = v
    d.data = current
    return d.__dict__


@app.get("/datasets/{dataset_name}")
async def get_dataset(dataset_name: str):
    d = DataSet(dataset_name)
    d = d.load_from_config()
    if hasattr(d, 'is_public') and d.is_public is False:
        # 数据集不是共有数据集
        return ResponseVO(702, "Illegal operation.")
    return d.__dict__


@app.get("/datasets/{dataset_name}")
async def get_datasets():
    d = DataDict()
    d = d.load_from_config()
    previous = d.data
    current = dict()
    for k, v in previous.items():
        # 为了兼容，若没有is_public字段，视为共有数据集
        if 'is_public' not in v or v['is_public']:
            current[k] = v
    d.data = current
    return d.__dict__


# 主机
@app.get("/hosts")
async def get_hosts(dataset_name: str):
    d = DataSet(dataset_name)
    d = d.load_from_config()
    if hasattr(d, 'is_public') and d.is_public is False:
        # 数据集不是共有数据集
        return ResponseVO(702, "Illegal operation.")
    return d.machines


@app.get("/hosts/{host_name}")
async def get_host(host_name: str, dataset_name: str):
    d = DataSet(dataset_name)
    d = d.load_from_config()
    if hasattr(d, 'is_public') and d.is_public is False:
        # 数据集不是共有数据集
        return ResponseVO(702, "Illegal operation.")
    return d.machines[host_name].__dict__


# 数据源
@app.get("/sources")
async def get_sources(dataset_name: str, host_name: str):
    d = DataSet(dataset_name)
    d = d.load_from_config()
    if hasattr(d, 'is_public') and d.is_public is False:
        # 数据集不是共有数据集
        return ResponseVO(702, "Illegal operation.")
    return d.machines[host_name].sources


@app.get("/sources/{source_name}")
async def get_host(source_name: str, dataset_name: str, host_name: str):
    d = DataSet(dataset_name)
    d = d.load_from_config()
    if hasattr(d, 'is_public') and d.is_public is False:
        # 数据集不是共有数据集
        return ResponseVO(702, "Illegal operation.")
    return d.machines[host_name].sources[source_name].__dict__


# 字段
@app.get("/columns")
async def get_columns(dataset_name: str, host_name: str, source_name: str):
    d = DataSet(dataset_name)
    d = d.load_from_config()
    if hasattr(d, 'is_public') and d.is_public is False:
        # 数据集不是共有数据集
        return ResponseVO(702, "Illegal operation.")
    return d.machines[host_name].sources[source_name].columns


if __name__ == "__main__":
    log_config = uvicorn.config.LOGGING_CONFIG
    log_config["formatters"]["access"]["fmt"] = "%(asctime)s - %(levelname)s - %(message)s"
    log_config["formatters"]["default"]["fmt"] = "%(asctime)s - %(levelname)s - %(message)s"
    uvicorn.run(app="main:app", host="0.0.0.0", port=31415, log_config=log_config)
